﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;

namespace CollabXT.Generator
{
    
    public enum WizardStates
    { Start, WITs, Queries, Libraries, Reports, End}
    public partial class WizardForm : Form
    {
        private const string executable = "\\vmxt-merge.exe";
        /// <summary>
        /// The directory containing the scaffolding files
        /// </summary>
        String dirScaffolding;
        /// <summary>
        /// The directory containing the scaffolding files
        /// </summary>
        public String Scaffolding
        {
            get { return dirScaffolding; }
            set {
                this.textTFS.Text = value;
                this.folderBrowser.SelectedPath = value;
                dirScaffolding = value;}
        }
        /// <summary>
        /// The directory containing the microprocess TFS template
        /// </summary>
        String dirMicro;
        /// <summary>
        /// The directory containing the microprocess TFS template
        /// </summary>
        public String MicroProcess
        {
            get { return dirMicro; }
            set { dirMicro = value;
            this.textMicro.Text = value;
            this.folderBrowser.SelectedPath = value;}
        }
        /// <summary>
        /// Tells us in which state/page the wizard is
        /// </summary>
        WizardStates state;
        /// <summary>
        /// The directory to the work item types relative to the process template directory
        /// </summary>
        const String witDir = "WorkItem Tracking\\TypeDefinitions";
        /// <summary>
        /// The directory to the queries relative to the process template directory
        /// </summary>
        const String queryDir = "WorkItem Tracking\\Queries";
        /// <summary>
        /// The directory to the reports relative to the process template directory
        /// </summary>
        const String reportDir = "Reports";
        /// <summary>
        /// The directory where the document libraries are stored
        /// </summary>
        const String integratedDir = "vmxt2tfs-integrated";
        /// <summary>
        /// The directory where the integrated scaffolding is stored
        /// </summary>
        const String libDir = "Windows Sharepoint Services";
        /// <summary>
        /// This event sends the data collected by the wizard when the Wizard finishes.
        /// </summary>
        public event IntegrationEventHandler Integrated;
        public WizardForm()
        {
            dirScaffolding = "";
            dirMicro = "";
            InitializeComponent();
            transitionToStart();
        }
        /// <summary>
        /// resets the wizard state, returning us to the first page
        /// </summary>
        public void Reset()
        {
            transitionToStart();
        }
        /// <summary>
        /// Transition to Start. Show the 1st page
        /// </summary>
        private void transitionToStart()
        {
            hidePages();
            this.panelStart.Visible = true;
            this.buttonNext.Text = "&Next";
            this.buttonPrevious.Enabled = false;
            labelStatus.Visible = false;
            state = WizardStates.Start;
        }
        /// <summary>
        /// Transition to the WIT lists. Show the 2nd page
        /// </summary>
        private void transitionToWITs()
        {           
            if (validateTemplateDir(Scaffolding) && validateTemplateDir(MicroProcess))
            {               
                buttonPrevious.Enabled = true;
                hidePages();
                pageWITs.Clear();
                scanWITs();
                pageWITs.Visible = true;
                state = WizardStates.WITs;
            }
        }
        private void scanWITs()
        {
            string scaffoldingPath = Path.Combine(Scaffolding, witDir);
            string microPath = Path.Combine(MicroProcess, witDir);
            string[] scaffoldingWITs = System.IO.Directory.GetFiles(scaffoldingPath, "*.xml");
            foreach (string wit in scaffoldingWITs)
            {
                System.IO.FileInfo info = new System.IO.FileInfo(wit);
                int index = pageWITs.LeftList.Items.Add(info.Name);
                pageWITs.LeftList.SetItemChecked(index, true);
            }

            string[] microWITs = System.IO.Directory.GetFiles(microPath, "*.xml");
            foreach (string wit in microWITs)
            {
                System.IO.FileInfo info = new System.IO.FileInfo(wit);
                pageWITs.RightList.Items.Add(info.Name);
            }
        }
        /// <summary>
        /// Transition to the query lists. Show the 3rd page
        /// </summary>
        private void transitionToQueries()
        {
            hidePages();
            pageQueries.Clear();
            scanQueries();
            pageQueries.Visible = true;
            buttonNext.Text = "&Next";
            state = WizardStates.Queries;
        }
        private void scanQueries()
        {            
            string scaffoldingPath = Path.Combine(Scaffolding, queryDir);
            string microPath = Path.Combine(MicroProcess, queryDir);
            string[] scaffoldingQs = System.IO.Directory.GetFiles(scaffoldingPath, "*.wiq");
            foreach (string q in scaffoldingQs)
            {
                System.IO.FileInfo info = new System.IO.FileInfo(q);
                int index = pageQueries.LeftList.Items.Add(info.Name);
                pageQueries.LeftList.SetItemChecked(index, true);
            }
            string[] microQs = System.IO.Directory.GetFiles(microPath, "*.wiq");
            foreach (string q in microQs)
            {
                System.IO.FileInfo info = new System.IO.FileInfo(q);
                pageQueries.RightList.Items.Add(info.Name);
            }
        }
        private void transitionToLibraries()
        {
            hidePages();
            scanLibraries();
            panelLibs.Visible = true;
            buttonNext.Text = "&Next";
            state = WizardStates.Libraries;
        }
        private void scanLibraries()
        {
            listLibs.Items.Clear();
            string microPath = Path.Combine(MicroProcess, libDir);
            string[] microQs = System.IO.Directory.GetDirectories(microPath);
            foreach (string q in microQs)
            {
                System.IO.DirectoryInfo info = new System.IO.DirectoryInfo(q);
                if (info.Name != "Process Guidance")
                {
                    listLibs.Items.Add(info.Name);
                }
            }
            if (listLibs.Items.Count == 0)
            {
                labelStatus.Text = "No document libraries found in the microprocess template";
                labelStatus.Visible = true;
            }
        }
        /// <summary>
        /// Transition to the report selection page
        /// </summary>
        private void transitionToReports()
        {
            hidePages();
            pageReports.Clear();
            scanReports();
            pageReports.Visible = true;
            buttonNext.Text = "&Next";
            state = WizardStates.Reports;
        }
        private void scanReports()
        {
            string scaffoldingPath = Path.Combine(Scaffolding, reportDir);
            string microPath = Path.Combine(MicroProcess, reportDir);
            string[] scaffoldingRs = System.IO.Directory.GetFiles(scaffoldingPath, "*.rdl");
            foreach (string q in scaffoldingRs)
            {
                System.IO.FileInfo info = new System.IO.FileInfo(q);
                int index = pageReports.LeftList.Items.Add(info.Name);
                pageReports.LeftList.SetItemChecked(index, true);
            }
            string[] microRs = System.IO.Directory.GetFiles(microPath, "*.rdl");
            foreach (string q in microRs)
            {
                System.IO.FileInfo info = new System.IO.FileInfo(q);
                pageReports.RightList.Items.Add(info.Name);
            }
        }
        /// <summary>
        /// Transition to End. Show the last page
        /// </summary>
        private void transitionToEnd()
        {
            hidePages();
            panelFinish.Visible = true;
            this.buttonNext.Text = "&Finish";
            state = WizardStates.End;
        }
        /// <summary>
        /// Finish the wizard's work
        /// </summary>
        private void transitionFinish()
        {
            IntegrationEventArgs data = collectData();
            createIntegratedScaffolding(data);
            if (callMergeUtility(data))
            {
                OnIntegrated(data);
                this.Close();
            }
        }
        /// <summary>
        /// validates that the we have valid values for the template directories
        /// </summary>
        /// <param name="templateDir"></param>
        /// <returns></returns>
        private bool validateTemplateDir(string templateDir)
        {
            labelStatus.Visible = false;
            labelStatus.ForeColor = Color.Red;
            if (templateDir == null || templateDir == "")
            {
                labelStatus.Text = String.Format("'{0}' does not appear to be a TFS template directory", templateDir);
                labelStatus.Visible = true;
                return false;
            }
            else
            {
                if (!System.IO.Directory.Exists(Path.Combine(templateDir, witDir)) || !System.IO.Directory.Exists(Path.Combine(templateDir, queryDir)))
                {
                    labelStatus.Text = String.Format("'{0}' does not appear to be a TFS template directory", templateDir);
                    labelStatus.Visible = true;
                    return false;
                }
            }
            return true;
        }
        /// <summary>
        /// Collects all the data and packs it into a IntegrationEvents instance
        /// </summary>
        /// <returns></returns>
        private IntegrationEventArgs collectData()
        {
            labelStatus.Text = "Collecting integration data";
            labelStatus.Visible = true;
            IntegrationEventArgs ret = new IntegrationEventArgs();
            //query files 
            string scaffoldingPath = Path.Combine(Scaffolding,queryDir);
            string microPath = Path.Combine(MicroProcess,queryDir);
            foreach(string name in pageQueries.RightList.CheckedItems)
            {
                ret.MicroQueries.Add(new FileInfo(Path.Combine(microPath,name)));
            }
            foreach (string name in pageQueries.LeftList.CheckedItems)
            {
                ret.ScaffoldingQueries.Add(new FileInfo(Path.Combine(scaffoldingPath,name)));
            }
            //WITs
            scaffoldingPath = Path.Combine(Scaffolding,witDir);
            microPath = Path.Combine(MicroProcess,witDir);
            foreach (string name in pageWITs.RightList.CheckedItems)
            {
                ret.MicroWITs.Add(new FileInfo(Path.Combine(microPath,name)));
            }
            foreach (string name in pageWITs.LeftList.CheckedItems)
            {
                ret.ScaffoldingWITs.Add(new FileInfo(Path.Combine(scaffoldingPath,name)));
            }
            //reports
            scaffoldingPath = Path.Combine(Scaffolding, reportDir);
            microPath = Path.Combine(MicroProcess, reportDir);
            foreach (string name in pageReports.RightList.CheckedItems)
            {
                ret.MicroReports.Add(new FileInfo(Path.Combine(microPath, name)));
            }
            foreach (string name in pageReports.LeftList.CheckedItems)
            {
                ret.ScaffoldingReports.Add(new FileInfo(Path.Combine(scaffoldingPath, name)));
            }
            //libraries
            microPath = Path.Combine(MicroProcess, libDir);
            foreach (string name in listLibs.CheckedItems)
            {
                ret.Libraries.Add(new DirectoryInfo(Path.Combine(microPath, name)));
            }
            //scaffolding directory
            ret.Scaffolding = new DirectoryInfo(Scaffolding);
            return ret;
        }
        /// <summary>
        /// Creates the temporary scaffolding copying the original scaffolding, 
        /// and the WITs, Queries and document libraries chosen by the user into a temporary directory
        /// </summary>
        /// <param name="data">the data collected by the wizard</param>
        void createIntegratedScaffolding(IntegrationEventArgs data)
        {
            labelStatus.Text = "Creating integrated scaffolding";
            //create it - ignores it if it exists
            data.IntegratedScaffolding = Directory.CreateDirectory(Path.Combine(System.IO.Path.GetTempPath(),integratedDir));
            //delete it anyway
            if (Directory.Exists(data.IntegratedScaffolding.FullName))
            {
                Directory.Delete(data.IntegratedScaffolding.FullName, true);
            }
            //copy the original scaffolding, without work items and queries
            CopyDirectory(data.Scaffolding,data.IntegratedScaffolding);
            //and because it's stupid, remove the WIT directories
            string witTypes=Path.Combine(data.IntegratedScaffolding.FullName, witDir);
            string queries = Path.Combine(data.IntegratedScaffolding.FullName, queryDir);
            Directory.Delete(witTypes, true);
            Directory.Delete(queries, true);
            //copy the erb templates from the WITs
            copyERBTemplates(data.IntegratedScaffolding.FullName);
            //and now copy the files defined in our data
            copyListOfFiles(witTypes,data.ScaffoldingWITs);
            copyListOfFiles(witTypes,data.MicroWITs);
            copyListOfFiles(queries,data.ScaffoldingQueries);
            copyListOfFiles(queries,data.MicroQueries);
            //handle the libraries
            foreach (DirectoryInfo dir in data.Libraries)
            {
                //copy the dir
                string target_dir=Path.Combine(data.IntegratedScaffolding.FullName,libDir);
                target_dir = Path.Combine(target_dir,dir.Name);
                CopyDirectory(dir, new DirectoryInfo(target_dir));
            }
            //handle the report stuff as well
            string reports = Path.Combine(data.IntegratedScaffolding.FullName, reportDir);
            Directory.Delete(reports,true);
            copyListOfFiles(reports, data.ScaffoldingReports);
            copyListOfFiles(reports, data.MicroReports);
        }
        private void copyERBTemplates(string target)
        {
            string scaffoldingPath = Path.Combine(Scaffolding, witDir);
            string[] scaffoldingWITs = System.IO.Directory.GetFiles(scaffoldingPath, "*.erb");
            foreach (string fi in scaffoldingWITs)
            {
                string filename = (new FileInfo(fi)).Name;
                string target_path=Path.Combine(target,witDir);
                if (!Directory.Exists(target_path))
                {
                    Directory.CreateDirectory(target_path);
                }
                File.Copy(fi,Path.Combine(target_path,filename), true);
            }
        }
        /// <summary>
        /// Copies a list of files into a directory 
        /// </summary>
        /// <param name="target">the target directory</param>
        /// <param name="files">the list of files</param>
        private void copyListOfFiles(string target, List<FileInfo> files)
        {
            foreach (FileInfo fi in files)
            {
                if (!Directory.Exists(target))
                {
                    Directory.CreateDirectory(target);
                }
                fi.CopyTo(Path.Combine(target, fi.Name), true);
            }
        }
        /// <summary>
        /// Copies a directory into another
        /// </summary>
        /// <param name="source">source directory</param>
        /// <param name="target">target directory</param>
        public static void CopyDirectory(DirectoryInfo source, DirectoryInfo target)
        {
            // Check if the target directory exists, if not, create it.
            if (Directory.Exists(target.FullName) == false)
            {
                Directory.CreateDirectory(target.FullName);
            }

            // Copy each file into it's new directory.
            foreach (FileInfo fi in source.GetFiles())
            {
                FileInfo tgt=fi.CopyTo(Path.Combine(target.FullName.ToString(), fi.Name), true);
                tgt.Attributes= FileAttributes.Normal;
            }

            // Copy each subdirectory using recursion.
            foreach (DirectoryInfo diSourceSubDir in source.GetDirectories())
            {
                DirectoryInfo nextTargetSubDir =
                    target.CreateSubdirectory(diSourceSubDir.Name);
                CopyDirectory(diSourceSubDir, nextTargetSubDir);
            }
        }
        /// <summary>
        /// Calls vmxt-merge to perform report merging
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        private bool callMergeUtility(IntegrationEventArgs data)
        {
            labelStatus.Text = "Starting merge utility";
            String arguments = String.Format("--scaffolding \"{0}\" --micro \"{1}\" \"{2}\"",
                Scaffolding,MicroProcess,data.IntegratedScaffolding.FullName);
            processMerge.StartInfo.Arguments = arguments;
            try
            {
                this.processMerge.Start();
                processMerge.WaitForExit();
                if (processMerge.ExitCode == 0)
                {
                    return true;
                }
                else
                {
                    labelStatus.Text = "There was an error running the merge utility. Check the merge log";
                }
            }
            catch (Exception ex)
            {
                labelStatus.Text = String.Format("Merge failed: {0}",ex.Message);
            }
            return false;
        }
        /// <summary>
        /// hides all the panels
        /// </summary>
        private void hidePages()
        {
            labelStatus.Visible = false;
            panelStart.Visible = false;
            panelLibs.Visible = false;
            pageWITs.Visible = false;
            pageQueries.Visible = false;
            pageReports.Visible = false;
            panelFinish.Visible = false;
        }
        /// <summary>
        /// Runs the state chart forward
        /// </summary>
        private void buttonNext_Click(object sender, EventArgs e)
        {
            switch (state)
            {
                case WizardStates.Start:
                    transitionToWITs();
                    break;
                case WizardStates.WITs:
                    transitionToQueries();
                    break;
                case WizardStates.Queries:
                    transitionToLibraries();
                    break;
                case WizardStates.Libraries:
                    transitionToReports();
                    break;
                case WizardStates.Reports:
                    transitionToEnd();
                    break;
                case WizardStates.End:
                    transitionFinish();
                    break;
            }
        }
        private void buttonCancel_Click(object sender, EventArgs e)
        {
            this.Close();
        }
        private void tfsBrowse_Click(object sender, EventArgs e)
        {
            this.folderBrowser.ShowDialog();
            Scaffolding = this.folderBrowser.SelectedPath;
            this.textTFS.Text = Scaffolding;
        }
        private void microBrowse_Click(object sender, EventArgs e)
        {
            this.folderBrowser.ShowDialog();
            MicroProcess = this.folderBrowser.SelectedPath;
            this.textMicro.Text = MicroProcess;
        }
        private void textTFS_TextChanged(object sender, EventArgs e)
        {
            Scaffolding = textTFS.Text;
        }
        private void textMicro_TextChanged(object sender, EventArgs e)
        {
            MicroProcess = textMicro.Text;
        }
        /// <summary>
        /// Runs the state machine backwards
        /// </summary>
        private void buttonPrevious_Click(object sender, EventArgs e)
        {
            switch (state)
            {
                case WizardStates.Start:
                    break;
                case WizardStates.WITs:
                    transitionToStart();
                    break;
                case WizardStates.Queries:
                    transitionToWITs();
                    break;
                case WizardStates.Libraries:
                    transitionToQueries();
                    break;
                case WizardStates.Reports:
                    transitionToLibraries();
                    break;
                case WizardStates.End:
                    transitionToReports();
                    break;
            }
        }
        protected virtual void OnIntegrated(IntegrationEventArgs e)
        {
            if (Integrated != null)
            {
                Integrated(this, e);
            }
        }
    }
    public delegate void IntegrationEventHandler(object sender, IntegrationEventArgs e);
    /// <summary>
    /// Represents the integration information gathered by WizardForm.
    /// Is sent as data by the Integrated event of WizardForm
    /// </summary>
    public class IntegrationEventArgs : EventArgs
    {
        /// <summary>
        /// List of the Reports chosen from the scaffolding
        /// </summary>
        List<FileInfo> scaffoldingReports;
        /// <summary>
        /// List of the Reports chosen from the scaffolding
        /// </summary>
        public List<FileInfo> ScaffoldingReports
        {
            get { return scaffoldingReports; }
            set { scaffoldingReports = value; }
        }
        /// <summary>
        /// List of the Reports chosen from the microprocess template
        /// </summary>
        List<FileInfo> microReports;
        /// <summary>
        /// List of the Reports chosen from the microprocess template
        /// </summary>
        public List<FileInfo> MicroReports
        {
            get { return microReports; }
            set { microReports = value; }
        }
        /// <summary>
        /// List of the WITs chosen from the scaffolding
        /// </summary>
        List<FileInfo> scaffoldingWITs;
        /// <summary>
        /// List of the WITs chosen from the scaffolding
        /// </summary>
        public List<FileInfo> ScaffoldingWITs
        {
            get { return scaffoldingWITs; }
            set { scaffoldingWITs = value; }
        }
        /// <summary>
        /// List of the WITs chosen from the microprocess template
        /// </summary>
        List<FileInfo> microWITs;
        /// <summary>
        /// List of the WITs chosen from the microprocess template
        /// </summary>
        public List<FileInfo> MicroWITs
        {
            get { return microWITs; }
            set { microWITs = value; }
        }
        /// <summary>
        /// List of the Queries chosen from the scaffolding
        /// </summary>
        List<FileInfo> scaffoldingQueries;
        /// <summary>
        /// List of the Queries chosen from the scaffolding
        /// </summary>
        public List<FileInfo> ScaffoldingQueries
        {
            get { return scaffoldingQueries; }
            set { scaffoldingQueries = value; }
        }
        /// <summary>
        /// List of the Queries chosen from the microprocess template
        /// </summary>
        List<FileInfo> microQueries;
        /// <summary>
        /// List of the Queries chosen from the microprocess template
        /// </summary>
        public List<FileInfo> MicroQueries
        {
            get { return microQueries; }
            set { microQueries = value; }
        }
        /// <summary>
        /// The scaffolding directory
        /// </summary>
        DirectoryInfo scaffolding;
        /// <summary>
        /// The scaffolding directory
        /// </summary>
        public DirectoryInfo Scaffolding
        {
            get { return scaffolding; }
            set { scaffolding = value; }
        }
        /// <summary>
        /// The temporary scaffolding directory generated by the Wizard
        /// </summary>
        DirectoryInfo integratedScaffolding;
        /// <summary>
        /// The temporary scaffolding directory generated by the Wizard
        /// </summary>
        public DirectoryInfo IntegratedScaffolding
        {
            get { return integratedScaffolding; }
            set { integratedScaffolding = value; }
        }
        /// <summary>
        /// List of the document libraries chosen from the microprocess template
        /// </summary>
        List<DirectoryInfo> libraries;
        /// <summary>
        /// List of the document libraries chosen from the microprocess template
        /// </summary>
        public List<DirectoryInfo> Libraries
        {
            get { return libraries; }
            set { libraries = value; }
        }
        
        public IntegrationEventArgs()
        {
            scaffoldingWITs = new List<FileInfo>();
            scaffoldingQueries = new List<FileInfo>();
            scaffoldingReports = new List<FileInfo>();
            microWITs = new List<FileInfo>();
            microReports = new List<FileInfo>();
            microQueries = new List<FileInfo>();
            libraries = new List<DirectoryInfo>();
            scaffolding = null;
            integratedScaffolding = null;
        }
    }
}